package com.ymt.bpm.service.dingtalk;

import com.alibaba.fastjson.JSONObject;
import com.dingtalk.open.client.ServiceFactory;
import com.dingtalk.open.client.api.model.corp.CorpUserBaseInfo;
import com.dingtalk.open.client.api.model.corp.CorpUserDetail;
import com.dingtalk.open.client.api.service.corp.CorpUserService;
import com.dingtalk.open.client.utils.StringUtils;
import com.ymt.bpm.appboot.env.Caches;
import com.ymt.bpm.appboot.env.DingtalkProperties;
import com.ymt.bpm.dao.dingtalk.PTenantDdMappMapper;
import com.ymt.bpm.model.PTenantDdMapp;
import com.ymt.bpm.util.AES;
import com.ymt.bpm.util.dingtalk.AuthHelper;
import com.ymt.bpm.util.dingtalk.OApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;


@Service
@EnableConfigurationProperties(value = DingtalkProperties.class)
public class DDMAppService {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private PTenantDdMappMapper mapper;
    @Autowired
    private DingtalkProperties prop;
    @Autowired
    private DDCacheService ddcs;

    public JSONObject testget() {
        PTenantDdMapp mapp = mapper.selectByPrimaryKey(1L);
        return (JSONObject)JSONObject.toJSON(mapp);
    }

    public JSONObject getDdConfig(String pageUrl) throws OApiException {

        pageUrl = pageUrl.replace("#/", "");
        String[] args = pageUrl.split("\\?")[1].split("&");
        for (String arg : args) {
            if (arg.startsWith("a=")) {
                String ddAppIdEnc = arg.substring(2);
                return getConfigMapp(pageUrl, ddAppIdEnc);
            } else if (arg.startsWith("corpId=")) {
                String corpId= arg.substring(7);
                return getConfigIsvMapp(pageUrl, corpId);
            }
        }
        return null;
    }

    public JSONObject getDDUserInfo(String ddAppIdEnc,
                                    String code) throws OApiException {
        //get mapp info
        String ddAppId = AES.decrypt(ddAppIdEnc);
        PTenantDdMapp mapp = mapper.selectByPrimaryKey(Long.parseLong(ddAppId));

        String tenantId = mapp.getTenantId()!=null && mapp.getTenantId()>0 ? String.valueOf(mapp.getTenantId()) : null;
        //get accessToken from cache
        String accessToken = getAccessToken(tenantId, mapp);

        try {
            CorpUserService corpUserService = ServiceFactory.getInstance().getOpenService(CorpUserService.class);
            CorpUserBaseInfo userBaseInfo = corpUserService.getUserinfo(accessToken, code);
            CorpUserDetail user = corpUserService.getCorpUser(accessToken, userBaseInfo.getUserid());
            JSONObject rtn = (JSONObject) JSONObject.toJSON(user);
            if (!StringUtils.isEmpty(tenantId)) {
                rtn.put("tenantId", AES.encrypt(tenantId));
            }
            /*JSONObject rtn = new JSONObject();

            rtn.put("name", userjo.get("name"));
            rtn.put("mobile", userjo.get("mobile"));
            rtn.put("email", userjo.get("email"));
            rtn.put("active", userjo.get("active"));
            rtn.put("isAdmin", userjo.get("isAdmin"));
            rtn.put("isBoss", userjo.get("isBoss"));
            rtn.put("isHide", userjo.get("isHide"));
            rtn.put("isHide", userjo.get("isHide"));*/

            //check if loginName is set
            String mobile = rtn.getString("mobile");
            String email = rtn.getString("email");
            fetchLoginName(rtn, tenantId, mobile, email);
            //see DINGTALK_DIRECT_LOGIN in bpmp-engine
            rtn.put("authkeydd", AES.encrypt("DINGTALK_DIRECT_LOGIN"));

            return rtn;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private JSONObject getConfigMapp(String pageUrl, String ddAppIdEnc) throws OApiException {
        String ddAppId = AES.decrypt(ddAppIdEnc);
        PTenantDdMapp mapp = mapper.selectByPrimaryKey(Long.parseLong(ddAppId));

        String tenantId = mapp.getTenantId()!=null && mapp.getTenantId()>0 ? String.valueOf(mapp.getTenantId()) : null;

        JSONObject rtn = new JSONObject();

        //计算当前请求的jsapi的签名数据
        //如果签名数据是通过ajax异步请求的话，签名计算中的url必须是给用户展示页面的url
        /*String[] urlStrings = pageUrl.split("\\?");
        String url = null;
        String queryString = urlStrings.length==2 ? urlStrings[1] : null;
        if (queryString != null) {
            String queryStringEncode = URLDecoder.decode(queryString);
            url = urlStrings[0] + "?" + queryStringEncode;
        } else {
            url = urlStrings[0];
        }*/

        String nonceStr = prop.getNonceStr();
        long timeStamp = System.currentTimeMillis() / 1000;
        String signedUrl = pageUrl;
        String accessToken = null;
        String ticket = null;
        String signature = null;
        String agentId = mapp.getAgentId();

        //get accessToken from cache
        accessToken = getAccessToken(tenantId, mapp);

        //get ticket from cache
        ticket = getTicket(tenantId, mapp, accessToken);

        signature = AuthHelper.sign(ticket, nonceStr, timeStamp, signedUrl);

        rtn.put("jsticket", ticket);
        rtn.put("signature", signature);
        rtn.put("nonceStr", nonceStr);
        rtn.put("timeStamp", timeStamp);
        rtn.put("corpId", mapp.getCorpId());
        rtn.put("agentId", agentId);
        rtn.put("appId", ddAppIdEnc);
        rtn.put("appName", mapp.getDdAppName());
        rtn.put("appDesc", mapp.getDdAppDesc());

        return rtn;
    }

    private JSONObject getConfigIsvMapp(String pageUrl, String corpId) throws OApiException {
        PTenantDdMapp mapp = mapper.selectByPrimaryKey(Long.parseLong(corpId));

        String tenantId = mapp.getTenantId()!=null && mapp.getTenantId()>0 ? String.valueOf(mapp.getTenantId()) : null;

        JSONObject rtn = new JSONObject();

        String nonceStr = prop.getNonceStr();
        long timeStamp = System.currentTimeMillis() / 1000;
        String signedUrl = pageUrl;
        String accessToken = null;
        String ticket = null;
        String signature = null;
        String agentId = mapp.getAgentId();

        //get accessToken from cache
        accessToken = getAccessToken(tenantId, mapp);

        //get ticket from cache
        ticket = getTicket(tenantId, mapp, accessToken);

        signature = AuthHelper.sign(ticket, nonceStr, timeStamp, signedUrl);

        rtn.put("jsticket", ticket);
        rtn.put("signature", signature);
        rtn.put("nonceStr", nonceStr);
        rtn.put("timeStamp", timeStamp);
        rtn.put("corpId", mapp.getCorpId());
        rtn.put("agentId", agentId);
        rtn.put("appId", corpId);
        rtn.put("appName", mapp.getDdAppName());
        rtn.put("appDesc", mapp.getDdAppDesc());

        return rtn;
    }

    private String getAccessToken(String tenantId, PTenantDdMapp mapp) throws OApiException {
        String accessTokenKey = tenantId+"_accessToken";
        String accessToken = ddcs.get(Caches.Token.name(), accessTokenKey);
        if (accessToken==null) {
            accessToken = AuthHelper.getAccessToken(mapp, prop);
            ddcs.set(Caches.Token.name(), accessTokenKey, accessToken);
        }
        return accessToken;
    }

    private String getTicket(String tenantId, PTenantDdMapp mapp, String accessToken) throws OApiException {
        String ticketKey = tenantId+"_ticket";
        String ticket = ddcs.get(Caches.Token.name(), ticketKey);
        if (ticket==null) {
            ticket = AuthHelper.getJsapiTicket(mapp, accessToken);
            ddcs.set(Caches.Token.name(), ticketKey, ticket);
        }
        return ticket;
    }

    private void fetchLoginName(JSONObject rtn, String tenantId, String mobile, String email) throws OApiException {
        String key = tenantId+'_'+mobile+'_'+email;
        String loginName = ddcs.get(Caches.Token.name(), key);
        if (StringUtils.isEmpty(loginName)) {
            if (!StringUtils.isEmpty(mobile) || !StringUtils.isEmpty(email)) {
                Map<String, String> paramMap = new HashMap<String, String>();
                paramMap.put("tenantId", tenantId);
                paramMap.put("mobile", mobile);
                paramMap.put("email", email);
                loginName = mapper.selectLoginNameByEmailMobile(paramMap);
                if (StringUtils.isEmpty(loginName)) {
                    rtn.put("notregistered", true);
                    //do not set cache here
                } else {
                    rtn.put("loginName", loginName);
                    ddcs.set(Caches.Token.name(), key, loginName);
                }
            } else {
                throw new OApiException(-1, "Mobile and Email are all empty.");
            }
        } else {
            rtn.put("loginName", loginName);
        }
    }

}
